/**
 * typeof: 用计算机的底层二进制来判断数据类型
 *         使用方法： typeof xx
 *         优点：使用方便，性能高
 *         缺点：只能检验基本类型、object、function, 不能校验null (结果成object了)， Date、RegExp、Array等实例对象typeof的结果也是object
 * 
 * instanceof: 非专业用于校验数据类型的，临时被拉来充当壮丁的，判断一个实例对象是否继承自一个类
 *             使用方法： xxx instanceof XXX
 *             原理：右侧类的prototype是否出现在左侧的__proto__链上
 *                  即 xxx.__proto__ === XXX.prototype 或 xxx.__proto__.__proto__ === XXX.prototype，直到 xxx的原型链指向null为止。
 *            优点：能判断实例对象继承自什么类
 *            缺点：1.例如arr instanceof Array 为 true, arr instanceof Object 也为 true, 因为Object.prototype也出现在了arr的原型链上
 *                 2.可以改写实例对象的__proto__属性，此时就不准确了
 *                 3.不能判断基本类型  1 instansof Number => false , 但 new Number(1) instansof Number => true 
 * 
 * constructor: 非专业用于校验数据类型的，临时被拉来充当壮丁的，判断一个实例对象的构造函数是啥
 *             使用方法： xxx.constructor === XXX
 *             原理：取得是xxx.__proto__.constructor是否是构造函数XXX
 *             优点：1.arr.constructor === Array => true, arr.constructor === Object => false
 *                  2.可以判断基本类型
 *                  3.可随意更改对象的constructor属性
 *    
 * Object.prototype.toString.call(): 专业选手
 *            使用方法：Object.prototype.toString.call([]) => [Object Array]
 *            原理：本来是Object.prototype上用于判断数据类型的方法，其他数据类型可用call借用
 *            优点：专业，什么诗句类型都能判断出来
 * 
 * 总结：写个判断数据类型的方法，思路
 *      1.先判断val是否 == null (undefinedy也两等于null), 是的话直接返回 val + ''
 *      2.typeof val 是否是 object, 不是的话直接返回类型，是的话再调用Object.prototype.toString.call(val)获取类型返回。
 *              
 */

function Fn(){}
Fn.prototype = Object.create(Array) // 会把 fn.__proto__ 指向 Array.prototype
Fn.prototype.constructor = Fn // 不写这个constructor指向就给改写了
let fn = new Fn()
console.log(fn.constructor === Fn)
console.log(fn.constructor === Array)



